﻿Imports Contracts
Imports System.ComponentModel
Imports Windows7.Location
Imports System.Threading
Imports System.Reflection
Imports FlickrNet
Imports System.IO

<WpfServiceMetadata("GeoWallpaperAddin")> _
    Public Class GeoWallpaperAddinImpl
    Implements IWpfService
    Implements INotifyPropertyChanged
    Private _status As String
    Public Event StatusUpdated As EventHandler Implements IWpfService.StatusUpdated

    Private _optionsUI As New GeoWallpaperUserControl()
    Private loc As LocationProvider = Nothing
    Private updateTimer As System.Threading.Timer
    Private rnd As New Random()


    Public Sub New()
        Console.WriteLine("GeoWallpaper starting up!")
        updateTimer = New System.Threading.Timer(New TimerCallback(AddressOf UpdateWallpaper), Nothing, Timeout.Infinite, Timeout.Infinite)

        FlickrTags = My.Settings.FlickrTags
        AutoUpdateInterval = My.Settings.AutoUpdate
        AutoUpdateEnabled = My.Settings.AutoUpdateEnabled

        _optionsUI.DataContext = Me
    End Sub

#Region "Service properties"

    Public ReadOnly Property OptionsUserControl() As System.Windows.Controls.UserControl Implements IWpfService.OptionsUserControl
        Get
            Return _optionsUI
        End Get
    End Property

    Public ReadOnly Property Name() As String Implements IWpfService.Name
        Get
            Return "GeoWallpaper"
        End Get
    End Property

    Public ReadOnly Property AddinIconUri() As Uri Implements IWpfService.AddinIconUri
        Get
            Dim u As String = CreateResourceUri("Globe.png")

            Return New Uri(u)
        End Get
    End Property

    Private Function CreateResourceUri(ByVal name As String) As String
        Dim a As Assembly = Assembly.GetExecutingAssembly()
        Return String.Format("pack://application:,,,/{0};component/Resources/{1}", a.GetName().Name, name)
    End Function

    Public ReadOnly Property Description() As String Implements IWpfService.Description
        Get
            Return "Updates your wallpaper based on current location (requires Windows 7+)"
        End Get
    End Property

    Public ReadOnly Property Author() As String Implements IWpfService.Author
        Get
            Return "Arian T. Kulp"
        End Get
    End Property

    Public ReadOnly Property Version() As Version Implements IWpfService.Version
        Get
            Return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version
        End Get
    End Property

    Public ReadOnly Property AuthorUri() As Uri Implements IWpfService.AuthorUri
        Get
            Return New Uri("http://www.ariankulp.com/")
        End Get
    End Property

    Public ReadOnly Property UpdateUri() As Uri Implements IWpfService.UpdateUri
        Get
            Return New Uri("http://www.ariankulp.com/downloads/")
        End Get
    End Property

    Public Property Status() As String Implements IWpfService.Status
        Get
            Return _status
        End Get
        Set(ByVal value As String)
            If value <> _status Then
                _status = value

                RaiseEvent StatusUpdated(Me, Nothing)
            End If
        End Set
    End Property

#End Region

    Public Sub Initialize() Implements IWpfService.Initialize
        _optionsUI.DataContext = Me
    End Sub

    Public Sub Start() Implements IWpfService.Start

        If Not EnvironmentSupport.MeetsOrExceeds(PlatformVersion.WINDOWS_7) Then
            ' Fatal error
            Throw New UtilityRuntimeException("The GeoWallpaper addin requires Windows 7 or higher to operate")
        ElseIf String.IsNullOrEmpty(My.Settings.FlickrKey) Or String.IsNullOrEmpty(My.Settings.FlickrSecret) Then
            Throw New UtilityRuntimeException("This application requires a Flickr API key.")
        Else
            OptionsUserControl.Dispatcher.Invoke(New Action(AddressOf StartupBackground))
        End If
    End Sub

    Private Sub StartupBackground()
        F = New Flickr(My.Settings.FlickrKey, My.Settings.FlickrSecret)
        If Not String.IsNullOrEmpty(My.Settings.AuthToken) Then
            F.AuthToken = My.Settings.AuthToken
        End If

        loc = New LatLongLocationProvider(10000)
        AddHandler loc.LocationChanged, New LocationChangedEventHandler(AddressOf loc_LocationChanged)
        lastLocation = loc.GetReport()

        FindNearbyImages()
        UpdateInterval()
        Status = "GeoWallpaper is started!"
    End Sub

    Private Sub loc_LocationChanged(ByVal locationProvider As LocationProvider, ByVal newLocation As LocationReport)
        Status = "Got a location"
        FindNearbyImages(TryCast(newLocation, LatLongLocationReport))
        UpdateWallpaper()
    End Sub

    Public Sub UpdateInterval()
        My.Settings.Save()

        If AutoUpdateEnabled Then
            updateTimer.Change(0, AutoUpdateInterval * 1000)
        Else
            updateTimer.Change(Timeout.Infinite, Timeout.Infinite)
        End If
    End Sub

    Private _flickrTags As String
    Public Property FlickrTags() As String
        Get
            Return _flickrTags
        End Get
        Set(ByVal value As String)
            _flickrTags = value

            NotifyPropertyChanged("FlickrTags")
        End Set
    End Property

    Private _lastPhoto As Photo
    Public Property LastPhoto() As Photo
        Get
            Return _lastPhoto
        End Get
        Set(ByVal value As Photo)
            _lastPhoto = value

            NotifyPropertyChanged("LastPhoto")
        End Set
    End Property

    ' The number of seconds between refreshes (if enabled)
    Private _autoUpdateInterval As Integer
    Public Property AutoUpdateInterval() As Integer
        Get
            Return _autoUpdateInterval
        End Get
        Set(ByVal value As Integer)
            _autoUpdateInterval = value
            NotifyPropertyChanged("AutoUpdateInterval")
        End Set
    End Property

    Private _autoUpdateEnabled As Boolean
    Public Property AutoUpdateEnabled() As Boolean
        Get
            Return _autoUpdateEnabled
        End Get
        Set(ByVal value As Boolean)
            _autoUpdateEnabled = value

            NotifyPropertyChanged("AutoUpdateEnabled")
        End Set
    End Property

    Private F As Flickr
    Private photos As Photo() = Nothing
    Private photoIdx As Integer = 0
    Private lastLocation As LatLongLocationReport
    Private tempFrob As String

    Public Sub BeginUserAuth()
        ' Get Frob    
        tempFrob = F.AuthGetFrob()
        ' Calculate the URL at Flickr to redirect the user to
        Dim flickrUrl As String = F.AuthCalcUrl(tempFrob, AuthLevel.Read)
        ' The following line will load the URL in the users default browser.
        System.Diagnostics.Process.Start(flickrUrl)
    End Sub

    Public Sub CompleteUserAuth()
        Try
            ' use the temporary Frob to get the authentication
            Dim auth As Auth = F.AuthGetToken(tempFrob)

            ' Store this Token for later usage, or set your Flickr instance to use it.
            F.AuthToken = auth.Token
            My.Settings.AuthToken = F.AuthToken
            My.Settings.Save()

            Status = "Flickr authorization successful"
        Catch ex As FlickrException
            ' If user did not authenticate your application then a FlickrException will be thrown.
            MessageBox.Show("Authentication did not succeed (" + ex.Message & ").  Please try again if you wish.")
        End Try
    End Sub

    Public Sub FindNearbyImages()
        If lastLocation IsNot Nothing Then
            OptionsUserControl.Dispatcher.Invoke(Function() FindNearbyImagesFunc())
        End If
    End Sub

    Private Function FindNearbyImagesFunc()
        FindNearbyImages(lastLocation)
        Return Nothing
    End Function


    ' TODO: Do nothing if location change is not significant enough
    Public Sub FindNearbyImages(ByVal location As LatLongLocationReport)
        Try
            Dim searchOptions As New PhotoSearchOptions()
            searchOptions.Tags = FlickrTags
            searchOptions.TagMode = TagMode.AnyTag
            searchOptions.Latitude = location.Latitude
            searchOptions.Longitude = location.Longitude
            searchOptions.Extras = PhotoSearchExtras.OwnerName

            photos = F.PhotosSearch(searchOptions).PhotoCollection

            My.Settings.FlickrTags = FlickrTags
            My.Settings.Save()
            photoIdx = rnd.Next(0, photos.Length - 1)
            lastLocation = location
        Catch x As Exception
            Status = "Flickr exception: " + x.Message
        End Try
    End Sub

    Public Sub UpdateWallpaper(ByVal unused As Object)
        Me.OptionsUserControl.Dispatcher.Invoke(DirectCast(AddressOf UpdateWallpaper, Action))
    End Sub

    Public Sub UpdateWallpaper()
        updateTimer.Change(Timeout.Infinite, Timeout.Infinite)

        Try
            If photos IsNot Nothing AndAlso photos.Length > 0 Then
                Dim photo As Photo = photos(photoIdx)

                photoIdx += 1
                If photoIdx = photos.Length Then
                    photoIdx = 0
                End If

                Dim fn As String = Path.Combine(Path.GetTempPath(), photo.PhotoId + "_" + photo.Secret & ".jpg")

                ' If we've already cached it don't download it again
                If Not File.Exists(fn) Then
                    Dim s As Sizes = F.PhotosGetSizes(photo.PhotoId)

                    ' Use the highest quality available
                    Dim url As String = s.SizeCollection(s.SizeCollection.Length - 1).Source

                    Dim ds As Stream = F.DownloadPicture(url)
                    Dim fs As IO.Stream = New FileStream(fn, FileMode.CreateNew)
                    ds.CopyTo(fs)
                    fs.Close()
                    ds.Close()
                End If

                Status = ("Now showing '" + photo.Title & "' by ") + photo.OwnerName

                LastPhoto = photo

                Wallpaper.SetWallpaper(fn, WallpaperStyle.Fit)
            Else
                Status = "No photos found for this location"
            End If
        Catch x As Exception
            Status = "Error updating wallpaper: " + x.Message
        Finally
            If AutoUpdateEnabled Then
                updateTimer.Change(AutoUpdateInterval * 1000, AutoUpdateInterval * 1000)
            End If
        End Try
    End Sub

    Public Sub [Stop]() Implements IWpfService.Stop
        updateTimer.Change(Timeout.Infinite, Timeout.Infinite)

        Status = "GeoWallpaper Stopped"
    End Sub

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Private Sub NotifyPropertyChanged(ByVal prop As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
    End Sub

#Region "IWpfService Members"


    Public ReadOnly Property HideOnClose() As Boolean
        Get
            Return True
        End Get
    End Property

#End Region
End Class
